#include "std_thread.h"

int std_thread() {
    //! 1. 线程和线程对象的创建
    std::thread t1(func1);      // 使用无参的func函数创建线程和线程对象, t1是线程对象，后台与某个线程绑定

    //! 线程对象创建时即与线程绑定, 而且立即开始执行
    // join()是确保到这一行的时候, t1对应的线程已经执行完成, join是一个阻塞函数，会阻塞当前线程
    // 如果不加这一行, 当前线程会继续往下执行, 然后随着主函数返回
    // 但，返回时t1除了作用域就会释放， 但其绑定的后台线程不一定执行完成了, 所以程序可能会有问题
    t1.join();

    // 给函数传参数
    std::thread t2(func2, 1, 3.14, "yangxian");
    t2.join();

    //! join只是强制阻塞等待线程执行完成, 函数的返回值将会被忽略
    // 要获取函数的返回值，我们可参考后续的异步线程部分


    //! 2. 线程对象与线程分离
    //! detach是将线程对象t1与后端绑定的线程进行解绑，这是t1不在对当时的线程有控制权限
    // 此时的后端线程由操作系统接管, 程序层面已经失去对后端线程的控制权
    // 程序也不能再次使用join重新获取对分离的线程的控制权
    //! detach是非阻塞的方法，主线程可以继续执行后续的代码
    std::thread t3(func1); 
    //! t3出了作用域也会析构, 但是其因为不再代表任何线程，所以析构了也没关系, os依然会控制对应的线程执行
    t3.detach();                     // 由于失去了控制权，如果func出现异常，我们也不能进行处理


    //! 3. 线程移动
    //! 查看thread的源码会发现: 其拷贝构造和拷贝赋值都被delete掉了
    // 但是其移动构造和移动赋值都在
    // std::thread t5 = t2;             //! Error
    std::thread t5 = std::move(t2);
    std::cout << std::boolalpha << t5.joinable() << std::endl;        // false


    //! 4. 现成的基本用法
    // 4.1. 获取线程信息
    std::cout << t5.get_id() << std::endl;                            // 获取某个线程的id
    std::cout << std::thread::hardware_concurrency() << std::endl;    // 获取CPU核心数

    // 4.2. 线程休眠
    std::thread t6(func3, 4);
    t6.detach();                                                      // 避免影响测试
    // t6.join();

    return 0;
}